/**
 * 
 */
package com.tompai.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
import java.util.ResourceBundle;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * mybatis获取数据库操作的简单单例模式
 * 
 * @author zhengchao1991
 *
 */
public class MybatisSqlSessionUtil {
	// public static final Logger LOGGER =
	// LoggerFactory.getLogger(TwitterAcountCrawlerDemo.class);

	public static final int DEFAULT_DB_LOGIN_TIMEOUT_SEC = 3;

	private static final String JDBC_CONFIG = "jdbc";// 默认jdbc配置文件名
	private static final String MYBATIS_CONFIG = "mybatis-config.xml";// mybatis配置文件名
	private static int DB_LOGIN_TIMEOUT_SEC = DEFAULT_DB_LOGIN_TIMEOUT_SEC;
	private static String KEY_PLUGIN_DB_URL = "PluginDBURL";
	private static String KEY_PLUGIN_DB_USER = "PluginDBUser";
	private static String KEY_PLUGIN_DB_PWD = "PluginDBPWD";

	private static ThreadLocal<SqlSession> sqlSessionThreadLocal = new ThreadLocal<>();

	public <T> T getMapper(Class<T> type) {
		SqlSession sqlSession = openSqlSession(false);
		if (sqlSession == null) {
			return null;
		}
		return sqlSession.getMapper(type);
	}

	public static SqlSession openSqlSession(boolean autoCommit) {
		SqlSession sqlSession = sqlSessionThreadLocal.get();
		if (sqlSession == null) {
			SqlSessionFactory sqlSessionFactory = MybatisSqlSessionFactorySingleton.INSTANCE.getSqlSessionFactory();
			if (sqlSessionFactory == null) {
				return null;
			}
			sqlSession = sqlSessionFactory.openSession(autoCommit);
			boolean isConnected = testGetConnection(sqlSession);
			if (!isConnected) {
				return null;
			}
			sqlSessionThreadLocal.set(sqlSession);
		}
		return sqlSession;
	}

	public static SqlSession openSqlSession(boolean autoCommit, int dbLoginTimeoutSec) {
		DB_LOGIN_TIMEOUT_SEC = dbLoginTimeoutSec;
		return openSqlSession(autoCommit);
	}

	private static boolean testGetConnection(SqlSession sqlSession) {
		Connection connection = null;
		try {
			// 后面的代码中再getConnection会取到同一个connection对象, 所以不需要关闭, 也不会影响性能
			connection = sqlSession.getConnection();
			if (connection != null) {
				return true;
			}
		} catch (Exception e) {
			// LOGGER.error("test sql error", e);
		}
		return false;
	}

	public static void closeSqlSession() {
		SqlSession sqlSession = sqlSessionThreadLocal.get();
		if (sqlSession != null) {
			sqlSession.close();
			sqlSessionThreadLocal.remove();
		}
	}

	private enum MybatisSqlSessionFactorySingleton {
		INSTANCE();

		private SqlSessionFactory sqlSessionFactory;

		MybatisSqlSessionFactorySingleton() {
			try {
				ResourceBundle bundle = ResourceBundle.getBundle(JDBC_CONFIG);
				String driverName = bundle.getString("driver").trim();

				/**
				 * System.getProperty(String key, String def) parameters: key the name of the
				 * system property. def a default value. Returns: the string value of the system
				 * property, or the default value if there is no property with that key.
				 */
				String url = System.getProperty(KEY_PLUGIN_DB_URL, bundle.getString("url")).trim();
				String userName = System.getProperty(KEY_PLUGIN_DB_USER, bundle.getString("username")).trim();
				String password = System.getProperty(KEY_PLUGIN_DB_PWD, bundle.getString("password")).trim();
				Properties properties = new Properties();
				properties.setProperty("driver", driverName);
				properties.setProperty("url", url);
				properties.setProperty("username", userName);
				properties.setProperty("password", password);
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(MYBATIS_CONFIG),
						properties);

				/**
				 * 数据库连接超时时间默认值
				 */
				if (DriverManager.getLoginTimeout() <= 0) {
					DriverManager.setLoginTimeout(DB_LOGIN_TIMEOUT_SEC);
				}
			} catch (Exception e) {
				// LOGGER.error("init SqlSessionFactory error", e);
			}
		}

		public SqlSessionFactory getSqlSessionFactory() {
			return sqlSessionFactory;
		}
	}

	private static class MybatisSqlSessionHelperHolder {
		private static final MybatisSqlSessionUtil INSTANCE = new MybatisSqlSessionUtil();

		private MybatisSqlSessionHelperHolder() {
		}
	}

	private MybatisSqlSessionUtil() {
	}

	public static final MybatisSqlSessionUtil getInstance() {
		return MybatisSqlSessionHelperHolder.INSTANCE;
	}
}